<?php
/**
 * Here the class '\UF\Config\ValueCollection' is defined.
 *
 * @category   UniKap-Framework
 * @package    Config
 * @subpackage Core
 * @author     Ulf -UniKado- Kadner <ulfikado@gmail.com>
 * @since      2014-03-29 16:17
 * @version    0.1
 */

namespace UF\Config
{

    /**
     * A associative collection of {@see \UF\Config\Value} elements
     *
     * @since      v0.1
     */
    class ValueCollection implements \ArrayAccess, \Serializable, \Iterator
    {

        # <editor-fold defaultstate="collapsed" desc="- - - -   P R I V A T E   F I E L D S   - - - - - - - - - - - - - - - - - - - - -">

        private $data;
        private $keys;
        private $position = 0;

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="- - - >   C O N S T R U C T O R   - - - - - - - - - - - - - - - - - - - - - - - -">

        /**
         * Inits a new empty instance.
         *
         * @since  v0.1
         */
        public function __construct()
        {
            $this->data = array();
            $this->keys = array();
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="- - - -   I M P L E M E N T   ' A r r a y A c c e s s '   - - - - - - - - - - - -">

        /**
         * Whether a offset exists.
         *
         * @param  mixed $offset An offset to check for.
	 * @return boolean <b>TRUE</b> on success or <b>FALSE</b> on failure.
         * @since  v0.1
         */
        public function offsetExists( $offset )
        {
            return isset( $this->data[$offset] );
        }

        /**
         * Offset to get.
         *
         * @param  string $offset
         * @return \UF\Config\Value
         * @since  v0.1
         */
        public function offsetGet( $offset )
        {
            return $this->data[$offset];
        }

        /**
         * Offset to set.
         *
         * @param  string $offset
         * @param  \UF\Config\Value $value
         * @return type
         * @throws \UF\ArgumentException
         * @since  v0.1
         */
        public function offsetSet( $offset, $value )
        {
            if ( \is_null( $offset ) || !\is_string( $offset ) ) { throw new \UF\ArgumentException(
                'offset', $offset, 'Illegal configvalue name-definition.' ); }
            if ( $offset != $value->name ) { throw new \UF\ArgumentException(
                'offset', $offset, 'Inconsistent config value name definition.' ); }
            if ( isset( $this->data[$offset] ) )
            {
                if ( \is_null( $value ) ) {
                    unset ( $this->data[$offset] ); $this->keys = \array_keys( $this->data ); return; }
                if ( !( $value instanceof \UF\Config\Value ) ) {
                    $this->data[$offset]->value = $value; $this->keys = \array_keys( $this->data ); return; }
                $this->data[$offset] = $value; $this->keys = \array_keys( $this->data ); return;
            }
            if ( !( $value instanceof \UF\Config\Value ) )
            {
                if ( \is_null( $value ) ) { throw new \UF\ArgumentException(
                'value', $value, \sprintf('Can not assign NULL value to config value "%s".', $offset) ); }
            }
            $this->data[$offset] = $value;
            $this->keys = \array_keys( $this->data );
        }

        /**
         * @param string $offset
         * @since  v0.1
         */
        public function offsetUnset( $offset )
        {
            unset ( $this->data[$offset] );
            $this->keys = \array_keys( $this->data );
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="- - - -   I M P L E M E N T   ' S e r i a l i z a b l e '   - - - - - - - - - - -">

        /**
         * Implements \Serializable
         *
         * @return string
         * @since  v0.1
         */
        public function serialize()
        {
            return \serialize( $this->data );
        }

        /**
         * Implements \Serializable
         *
         * @param  string $serialized
         * @throws \UF\ArgumentException
         * @since  v0.1
         */
        public function unserialize( $serialized )
        {
            $this->keys = array();
            try { $array = \unserialize( $serialized ); }
            catch ( \Exception $ex ) {
                $ex = null;
                throw new \UF\ArgumentException(
                    'serialized', $serialized,
                    'Unable to deserialize data if data do not use not a valid php serialization format!' );
            }
            if ( !\is_array( $array ) ) { throw new \UF\ArgumentException( 'serialized', $serialized,
                'Unable to deserialize config value data if data do not match required format!' ); }
            $this->data = array();
            foreach ( $array as $row )
            {
                if ( !( $row instanceof \UF\Config\Value ) ) { continue; }
                $this->data[$row->name] = $row;
            }
            $this->keys = \array_keys( $this->data );
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="- - - -   P U B L I C   M E T H O D S   - - - - - - - - - - - - - - - - - - - - -">

        /**
         * Return the current config value with the defined value, or $defaultValue in no value exists for $name.
         *
         * @param  string $name The name of the required config value
         * @param  mixed $defaultValue
         * @return \UF\Config\Value
         * @since  v0.1
         */
        public function getValue( $name, $defaultValue = null )
        {
            if ( !isset( $this->data[$name] ) ) { return $defaultValue; }
            return $this->data[$name];
        }

        /**
         * Returns the array with {@see \UF\Config\Value} elements.
         *
         * @return array
         * @since  v0.1
         */
        public function toArray()
        {
            return $this->data;
        }

        # </editor-fold>

        # <editor-fold defaultstate="collapsed" desc="- - - -   I M P L E M E N T   ' I t e r a t o r '   - - - - - - - - - - - - - - -">

        /**
         * Implements \Iterator::rewind().
         *
         * @since  v0.1
         */
        public function rewind()
        {
            $this->position = 0;
        }

        /**
         * Implements \Iterator::valid().
         *
         * @return boolean
         * @since  v0.1
         */
        public function valid()
        {
            return $this->position < \count( $this->data );
        }

        /**
         * Implements \Iterator::key().
         *
         * @since  v0.1
         * @return string
         */
        public function key()
        {
            return $this->keys[$this->position];
        }

        /**
         * Implements \Iterator::current().
         *
         * @since  v0.1
         * @return \UF\Config\Value
         */
        public function current()
        {
            return $this->data[$this->keys[$this->position]];
        }

        /**
         * Implements \Iterator::next().
         *
         * @since  v0.1
         */
        public function next()
        {
            $this->position++;
        }

        # </editor-fold>

    }

}

